# 工作流调度器
import logging
from typing import Dict, List, Optional
from django.utils import timezone
from django.db.models import Q
from datetime import datetime, timedelta
from django.contrib.auth.models import User
import json

from .models_workflow import WorkflowInstance, WorkflowStepTask, WorkflowSchedule
from .workflow_engine import WorkflowEngine
from .notification_service import notification_service

logger = logging.getLogger(__name__)


class WorkflowScheduler:
    """工作流调度器 - 处理定时任务、超时处理、自动化操作"""
    
    def __init__(self):
        self.workflow_engine = WorkflowEngine()
    
    def process_scheduled_workflows(self):
        """处理计划执行的工作流"""
        
        try:
            now = timezone.now()
            
            # 获取需要执行的计划任务
            scheduled_tasks = WorkflowSchedule.objects.filter(
                is_active=True,
                next_run_time__lte=now,
                status='active'
            )
            
            for schedule in scheduled_tasks:
                try:
                    self._execute_scheduled_workflow(schedule)
                except Exception as e:
                    logger.error(f"执行计划任务 {schedule.id} 失败: {e}")
                    schedule.last_error = str(e)
                    schedule.save()
            
            logger.info(f"处理了 {scheduled_tasks.count()} 个计划任务")
            
        except Exception as e:
            logger.error(f"处理计划工作流失败: {e}")
    
    def _execute_scheduled_workflow(self, schedule: WorkflowSchedule):
        """执行计划的工作流"""
        
        try:
            # 创建工作流实例
            instance = self.workflow_engine.create_workflow_instance(
                template_id=schedule.template.id,
                instance_name=f"{schedule.name} - {timezone.now().strftime('%Y%m%d_%H%M%S')}",
                related_object_type=schedule.target_object_type,
                related_object_id=schedule.target_object_id,
                created_by=schedule.created_by,
                initial_data=schedule.workflow_data
            )
            
            # 启动工作流
            success = self.workflow_engine.start_workflow(instance.id, schedule.created_by)
            
            if success:
                # 更新计划任务状态
                schedule.last_run_time = timezone.now()
                schedule.run_count += 1
                schedule.last_instance_id = instance.id
                
                # 计算下次执行时间
                schedule.next_run_time = self._calculate_next_run_time(schedule)
                
                # 检查是否达到最大执行次数
                if schedule.max_runs and schedule.run_count >= schedule.max_runs:
                    schedule.is_active = False
                    schedule.status = 'completed'
                
                schedule.save()
                
                logger.info(f"计划任务 {schedule.id} 执行成功，创建实例 {instance.id}")
            else:
                raise Exception("工作流启动失败")
                
        except Exception as e:
            logger.error(f"执行计划任务 {schedule.id} 失败: {e}")
            schedule.last_error = str(e)
            schedule.error_count += 1
            
            # 如果错误次数过多，停用计划任务
            if schedule.error_count >= 5:
                schedule.is_active = False
                schedule.status = 'error'
            
            schedule.save()
            raise
    
    def _calculate_next_run_time(self, schedule: WorkflowSchedule) -> datetime:
        """计算下次执行时间"""
        
        schedule_type = schedule.schedule_type
        current_time = timezone.now()
        
        if schedule_type == 'once':
            # 一次性任务，不再执行
            return None
        
        elif schedule_type == 'daily':
            # 每日执行
            return current_time + timedelta(days=1)
        
        elif schedule_type == 'weekly':
            # 每周执行
            return current_time + timedelta(weeks=1)
        
        elif schedule_type == 'monthly':
            # 每月执行（简化处理，加30天）
            return current_time + timedelta(days=30)
        
        elif schedule_type == 'cron':
            # Cron表达式（需要第三方库支持）
            # 这里简化处理，返回1小时后
            return current_time + timedelta(hours=1)
        
        else:
            # 默认1小时后
            return current_time + timedelta(hours=1)
    
    def process_overdue_tasks(self):
        """处理超时任务"""
        
        try:
            now = timezone.now()
            
            # 获取超时的任务
            overdue_tasks = WorkflowStepTask.objects.filter(
                status='pending',
                due_date__lt=now,
                due_date__isnull=False
            ).select_related('workflow_instance', 'assignee')
            
            for task in overdue_tasks:
                try:
                    self._handle_overdue_task(task)
                except Exception as e:
                    logger.error(f"处理超时任务 {task.id} 失败: {e}")
            
            logger.info(f"处理了 {overdue_tasks.count()} 个超时任务")
            
        except Exception as e:
            logger.error(f"处理超时任务失败: {e}")
    
    def _handle_overdue_task(self, task: WorkflowStepTask):
        """处理单个超时任务"""
        
        step_config = task.step_config
        timeout_config = step_config.get('timeout_handling', {})
        
        action = timeout_config.get('action', 'notify')
        
        if action == 'notify':
            # 发送超时通知
            self._send_overdue_notification(task)
        
        elif action == 'escalate':
            # 升级处理
            self._escalate_overdue_task(task)
        
        elif action == 'auto_approve':
            # 自动批准
            self._auto_approve_overdue_task(task)
        
        elif action == 'auto_reject':
            # 自动拒绝
            self._auto_reject_overdue_task(task)
        
        elif action == 'reassign':
            # 重新分配
            self._reassign_overdue_task(task)
        
        # 标记任务为已处理超时
        task.is_overdue_processed = True
        task.overdue_processed_at = timezone.now()
        task.save()
    
    def _send_overdue_notification(self, task: WorkflowStepTask):
        """发送超时通知"""
        
        recipients = []
        
        # 通知任务分配人
        if task.assignee:
            recipients.append(task.assignee)
        
        # 通知工作流创建者
        recipients.append(task.workflow_instance.created_by)
        
        # 通知管理员
        admin_users = User.objects.filter(is_superuser=True)
        recipients.extend(admin_users)
        
        # 去重
        recipients = list(set(recipients))
        
        overdue_hours = (timezone.now() - task.due_date).total_seconds() / 3600
        
        notification_service.send_notification(
            users=recipients,
            title=f"任务超时提醒: {task.step_name}",
            message=f"工作流任务 '{task.step_name}' 已超时 {overdue_hours:.1f} 小时，请及时处理。\n"
                   f"工作流: {task.workflow_instance.instance_name}\n"
                   f"分配人: {task.assignee.username if task.assignee else '未分配'}",
            channels=['system', 'email'],
            priority='high',
            action_url=f"/assets/workflow/tasks/{task.id}/"
        )
    
    def _escalate_overdue_task(self, task: WorkflowStepTask):
        """升级超时任务"""
        
        step_config = task.step_config
        escalation_config = step_config.get('escalation', {})
        
        # 获取升级目标用户
        escalate_to_type = escalation_config.get('escalate_to', 'manager')
        
        if escalate_to_type == 'manager':
            # 升级给管理员
            new_assignee = User.objects.filter(is_superuser=True).first()
        elif escalate_to_type == 'creator':
            # 升级给工作流创建者
            new_assignee = task.workflow_instance.created_by
        else:
            # 升级给指定用户
            user_id = escalation_config.get('user_id')
            if user_id:
                try:
                    new_assignee = User.objects.get(id=user_id)
                except User.DoesNotExist:
                    new_assignee = None
            else:
                new_assignee = None
        
        if new_assignee:
            old_assignee = task.assignee
            task.assign_to(new_assignee)
            
            # 发送升级通知
            notification_service.send_notification(
                users=[new_assignee],
                title=f"任务升级: {task.step_name}",
                message=f"由于任务超时，已将任务从 {old_assignee.username if old_assignee else '未分配'} "
                       f"升级给您处理。\n工作流: {task.workflow_instance.instance_name}",
                channels=['system', 'email'],
                priority='high',
                action_url=f"/assets/workflow/tasks/{task.id}/"
            )
    
    def _auto_approve_overdue_task(self, task: WorkflowStepTask):
        """自动批准超时任务"""
        
        # 使用系统用户自动批准
        system_user = User.objects.filter(username='system').first()
        if not system_user:
            system_user = User.objects.filter(is_superuser=True).first()
        
        if system_user:
            success = self.workflow_engine.complete_manual_task(
                task_id=task.id,
                operator=system_user,
                action='approve',
                comments='系统自动批准（任务超时）'
            )
            
            if success:
                # 发送自动批准通知
                notification_service.send_notification(
                    users=[task.workflow_instance.created_by],
                    title=f"任务自动批准: {task.step_name}",
                    message=f"由于任务超时，系统已自动批准任务。\n"
                           f"工作流: {task.workflow_instance.instance_name}",
                    channels=['system', 'email']
                )
    
    def _auto_reject_overdue_task(self, task: WorkflowStepTask):
        """自动拒绝超时任务"""
        
        # 使用系统用户自动拒绝
        system_user = User.objects.filter(username='system').first()
        if not system_user:
            system_user = User.objects.filter(is_superuser=True).first()
        
        if system_user:
            success = self.workflow_engine.complete_manual_task(
                task_id=task.id,
                operator=system_user,
                action='reject',
                comments='系统自动拒绝（任务超时）'
            )
            
            if success:
                # 发送自动拒绝通知
                notification_service.send_notification(
                    users=[task.workflow_instance.created_by],
                    title=f"任务自动拒绝: {task.step_name}",
                    message=f"由于任务超时，系统已自动拒绝任务。\n"
                           f"工作流: {task.workflow_instance.instance_name}",
                    channels=['system', 'email']
                )
    
    def _reassign_overdue_task(self, task: WorkflowStepTask):
        """重新分配超时任务"""
        
        step_config = task.step_config
        reassign_config = step_config.get('reassign', {})
        
        # 获取重新分配的目标
        reassign_to = reassign_config.get('reassign_to', 'group')
        
        if reassign_to == 'group':
            # 分配给用户组中的其他用户
            if task.assignee and hasattr(task.assignee, 'groups'):
                groups = task.assignee.groups.all()
                for group in groups:
                    other_users = group.user_set.exclude(id=task.assignee.id).filter(is_active=True)
                    if other_users.exists():
                        new_assignee = other_users.first()
                        task.assign_to(new_assignee)
                        
                        # 发送重新分配通知
                        notification_service.send_notification(
                            users=[new_assignee],
                            title=f"任务重新分配: {task.step_name}",
                            message=f"由于原分配人任务超时，现将任务分配给您。\n"
                                   f"工作流: {task.workflow_instance.instance_name}",
                            channels=['system', 'email'],
                            action_url=f"/assets/workflow/tasks/{task.id}/"
                        )
                        break
    
    def process_timer_tasks(self):
        """处理定时器任务"""
        
        try:
            now = timezone.now()
            
            # 获取到期的定时器任务
            timer_tasks = WorkflowStepTask.objects.filter(
                step_type='timer',
                status='pending',
                due_date__lte=now
            )
            
            for task in timer_tasks:
                try:
                    # 完成定时器任务
                    task.status = 'completed'
                    task.completed_at = now
                    task.save()
                    
                    # 继续工作流
                    self.workflow_engine._check_and_continue_workflow(task.workflow_instance)
                    
                except Exception as e:
                    logger.error(f"处理定时器任务 {task.id} 失败: {e}")
            
            logger.info(f"处理了 {timer_tasks.count()} 个定时器任务")
            
        except Exception as e:
            logger.error(f"处理定时器任务失败: {e}")
    
    def cleanup_old_instances(self, days: int = 90):
        """清理旧的工作流实例"""
        
        try:
            cutoff_date = timezone.now() - timedelta(days=days)
            
            # 获取需要清理的实例
            old_instances = WorkflowInstance.objects.filter(
                created_at__lt=cutoff_date,
                status__in=['completed', 'cancelled', 'failed']
            )
            
            cleanup_count = 0
            
            for instance in old_instances:
                try:
                    # 可以选择删除或归档
                    # 这里选择标记为已归档
                    instance.is_archived = True
                    instance.archived_at = timezone.now()
                    instance.save()
                    
                    cleanup_count += 1
                    
                except Exception as e:
                    logger.error(f"清理实例 {instance.id} 失败: {e}")
            
            logger.info(f"清理了 {cleanup_count} 个旧实例")
            
        except Exception as e:
            logger.error(f"清理旧实例失败: {e}")
    
    def generate_workflow_reports(self):
        """生成工作流报告"""
        
        try:
            now = timezone.now()
            
            # 生成日报
            self._generate_daily_report(now.date())
            
            # 如果是周一，生成周报
            if now.weekday() == 0:  # 周一
                week_start = now.date() - timedelta(days=7)
                self._generate_weekly_report(week_start)
            
            # 如果是月初，生成月报
            if now.day == 1:
                month_start = (now.replace(day=1) - timedelta(days=1)).replace(day=1)
                self._generate_monthly_report(month_start)
            
        except Exception as e:
            logger.error(f"生成工作流报告失败: {e}")
    
    def _generate_daily_report(self, report_date):
        """生成日报"""
        
        start_time = timezone.make_aware(datetime.combine(report_date, datetime.min.time()))
        end_time = start_time + timedelta(days=1)
        
        # 统计数据
        instances_created = WorkflowInstance.objects.filter(
            created_at__range=[start_time, end_time]
        ).count()
        
        instances_completed = WorkflowInstance.objects.filter(
            completed_at__range=[start_time, end_time]
        ).count()
        
        tasks_completed = WorkflowStepTask.objects.filter(
            completed_at__range=[start_time, end_time]
        ).count()
        
        overdue_tasks = WorkflowStepTask.objects.filter(
            status='pending',
            due_date__lt=end_time,
            due_date__gte=start_time
        ).count()
        
        # 发送报告给管理员
        admin_users = User.objects.filter(is_superuser=True)
        
        report_content = f"""
工作流日报 - {report_date.strftime('%Y年%m月%d日')}

今日统计:
- 创建工作流实例: {instances_created} 个
- 完成工作流实例: {instances_completed} 个  
- 完成任务: {tasks_completed} 个
- 新增超时任务: {overdue_tasks} 个

系统运行正常。
        """
        
        notification_service.send_notification(
            users=list(admin_users),
            title=f"工作流日报 - {report_date.strftime('%Y-%m-%d')}",
            message=report_content,
            channels=['system', 'email']
        )
    
    def _generate_weekly_report(self, week_start):
        """生成周报"""
        
        start_time = timezone.make_aware(datetime.combine(week_start, datetime.min.time()))
        end_time = start_time + timedelta(days=7)
        
        # 详细统计...
        # 实现类似日报的逻辑，但统计周数据
        pass
    
    def _generate_monthly_report(self, month_start):
        """生成月报"""
        
        # 详细统计...
        # 实现类似日报的逻辑，但统计月数据
        pass


# 创建全局实例
workflow_scheduler = WorkflowScheduler()